#include <iostream>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <assert.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>

#include "log.hpp"
#include "protocol.hpp"

using namespace std;

bool quit = false;
// hello
int main(int argc, char *argv[])
{
    cout << "hello" << endl;
    assert(argc == 3);
    // 首先提取客户端需要连接服务器端的ip和端口
    string serveip = argv[1];
    uint16_t serveport = atoi(argv[2]);
    // 1、创建客户端
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1)
    {
        LogMessage(FATAL, "socket:%s:%d", strerror(errno), sockfd);
    }
    LogMessage(DEBUG, "socket success:%d", sockfd);
    // 2、发送连接
    // 不用监听，因为客户端不会获取连接，没有人来连接客户端
    struct sockaddr_in serve;
    serve.sin_family = AF_INET;
    serve.sin_port = htons(serveport);
    serve.sin_addr.s_addr = inet_addr(serveip.c_str());
    socklen_t len = sizeof(serve);
    // connect发送连接，调用connect，会自动bind
    if (connect(sockfd, (struct sockaddr *)&serve, len) == -1)
    {
        LogMessage(FATAL, "connect:%s:%d", strerror(errno), sockfd);
        exit(1);
    }
    LogMessage(DEBUG, "conect success:%d", sockfd);
    // 3、向服务器端发送数据
    char buffer[1024];
    string message;
    while (!quit)
    {
        message.clear();
        // cout << "请输入你的消息>>> ";
        cout << "请输入你的表达式>>> ";
        getline(cin, message);
        if (strcasecmp(message.c_str(), "quit") == 0)
        {
            quit = true;
        }

        req request;
        if(!makeReuquest(message, &request)) continue;
        // req.debug();
        std::string package;
        request.serialize(&package); // done
        package = encode(package, package.size()); // done
        ssize_t s = write(sockfd, package.c_str(), package.size());
        if (s > 0)
        {
            message.resize(1024);
            ssize_t s = read(sockfd, (char *)message.c_str(), 1024);
            if (s > 0)
            {
                message[s] = 0;
            }
            int len = 0;
            string tmp = decode(message, &len);
            if (len > 0)
            {
                resp respon;
                respon.deserialize(tmp);
                if(respon.errcode_!=0)
                {
                    cout<<"failed errcode"<<respon.errcode_<<endl;
                    continue;
                }
                std::cout << "Server Echo>>> errcode: " << respon.errcode_ << " result: "
                          << respon.result_ << std::endl;
            }
            // std::cout << "Server Echo>>> " << message << std::endl;
        }
        else if (s <= 0)
        {
            break;
        }
    }
    close(sockfd);
    return 0;
}
